﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Web;
using ElectronicCommerce.Framework.Web.UI.GeneratedImage.ImageStore;
using ElectronicCommerce.Framework.Web.UI.GeneratedImage.ImageTransform;

namespace ElectronicCommerce.Framework.Web.UI.GeneratedImage
{
    /// <summary>
    /// 
    /// </summary>
    public class ImageHandlerInternal
    {
        // 客户端缓存时间默认为10分钟
        private static TimeSpan s_defaultClientCacheExpiration = new TimeSpan(0, 10, 0);

        private TimeSpan _clientCacheExpiration = s_defaultClientCacheExpiration;
        private IImageStore _imageStore;
        private DateTime? _now;

        public ImageHandlerInternal()
        {
            ContentType = ImageFormat.Jpeg;
            ImageTransforms = new List<ImageTransform.ImageTransform>();
        }

        internal ImageHandlerInternal(IImageStore imageStore, DateTime now)
            : this()
        {
            _imageStore = imageStore;
            _now = now;
        }

        /// <summary>
        /// 客户端图片缓存时间
        /// </summary>
        public TimeSpan ClientCacheExpiration
        {
            get
            {
                return _clientCacheExpiration;
            }
            set
            {
                if (value.Ticks < 0)
                {
                    throw new ArgumentOutOfRangeException("value", "ClientCacheExpiration must be positive");
                }
                _clientCacheExpiration = value;
                EnableClientCache = true;
            }
        }

        /// <summary>
        /// 图片类型
        /// </summary>
        public ImageFormat ContentType { get; set; }

        /// <summary>
        /// 请求图片处理时间
        /// </summary>
        private DateTime DateTime_Now
        {
            get
            {
                return _now ?? DateTime.Now;
            }
        }

        /// <summary>
        /// 图片存储
        /// </summary>
        private IImageStore ImageStore
        {
            get
            {
                return _imageStore ?? DiskImageStore.Instance;
            }
        }

        /// <summary>
        /// 是否启动浏览器缓存
        /// </summary>
        public bool EnableClientCache { get; set; }

        /// <summary>
        /// 是否存储在物理介质
        /// </summary>
        public bool EnableServerCache { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string VirtualPathRoot { get; set; }

        /// <summary>
        /// 图片转换器
        /// </summary>
        public List<ImageTransform.ImageTransform> ImageTransforms
        {
            get;
            private set;
        }

        /// <summary>
        /// 获取图片类型
        /// </summary>
        /// <param name="format"></param>
        /// <returns></returns>
        internal static string GetImageMimeType(ImageFormat format)
        {
            string mimeType = "image/x-unknown";

            if (format.Equals(ImageFormat.Gif))
            {
                mimeType = "image/gif";
            }
            else if (format.Equals(ImageFormat.Jpeg))
            {
                mimeType = "image/jpeg";
            }
            else if (format.Equals(ImageFormat.Png))
            {
                mimeType = "image/png";
            }
            else if (format.Equals(ImageFormat.Bmp) || format.Equals(ImageFormat.MemoryBmp))
            {
                mimeType = "image/bmp";
            }
            else if (format.Equals(ImageFormat.Tiff))
            {
                mimeType = "image/tiff";
            }
            else if (format.Equals(ImageFormat.Icon))
            {
                mimeType = "image/x-icon";
            }

            return mimeType;
        }

        /// <summary>
        /// 执行图片转换
        /// </summary>
        /// <param name="context"></param>
        /// <param name="imageGenCallback"></param>
        public void HandleImageRequest(HttpContextBase context, Func<ImageGenerateRequest, ImageInfo> imageGenCallback)
        {
            context.Response.Clear();
            context.Response.ContentType = GetImageMimeType(ContentType);

            var cachePolicy = context.Response.Cache;
            cachePolicy.SetValidUntilExpires(true);
            if (EnableClientCache)
            {
                cachePolicy.SetCacheability(HttpCacheability.Public);
                cachePolicy.SetExpires(DateTime_Now + ClientCacheExpiration);
            }

            ImageGenerateRequest generateRequest = GetImageGenerateRequest(context);
            if (EnableServerCache)
            {
                if (ImageStore.TryTransmitIfContains(generateRequest.ThumbnailImagePath, context.Response))
                {
                    context.Response.End();
                    return;
                }
            }

            ImageInfo imageMethodData = imageGenCallback(generateRequest);
            if (imageMethodData == null)
            {
                throw new InvalidOperationException("The image generation handler cannot return null.");
            }

            if (imageMethodData.HttpStatusCode != null)
            {
                context.Response.StatusCode = (int)imageMethodData.HttpStatusCode;
                context.Response.End();
                return;
            }

            MemoryStream imageOutputBuffer = new MemoryStream();

            Debug.Assert(!(imageMethodData.Image == null && imageMethodData.ImageByteBuffer == null));
            if (imageMethodData.Image != null)
            {
                RenderImage(GetImageThroughTransforms(imageMethodData.Image), imageOutputBuffer);
            }
            else if (imageMethodData.ImageByteBuffer != null)
            {
                RenderImage(GetImageThroughTransforms(imageMethodData.ImageByteBuffer), imageOutputBuffer);
            }

            byte[] buffer = imageOutputBuffer.GetBuffer();
            context.Response.OutputStream.Write(buffer, 0, buffer.Length);

            if (EnableServerCache)
            {
                if (!generateRequest.IsRequestOriginalImage)
                    ImageStore.Add(generateRequest.ThumbnailImagePath, buffer);
            }

            context.Response.End();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private ImageGenerateRequest GetImageGenerateRequest(HttpContextBase context)
        {
            // 获取原始图片名和默认显示图片名
            string originalImageName = ECContext.Current.GetFromQueryString("n");
            string defaultImageName = ECContext.Current.GetFromQueryString("dn");
            string thumbnailImageName = ECContext.Current.GetFromQueryString("tn");
            int requestWidth = ECContext.Current.GetFromQueryString<int>("w", 0);
            int requestHeight = ECContext.Current.GetFromQueryString<int>("h", 0);

            string originalImagePath = "";
            string defaultImagePath = "";

            // 获取原始图片和默认显示图片绝对路径
            if (!string.IsNullOrEmpty(originalImageName))
                originalImagePath = ECContext.Current.MapPath(string.Format("{0}/{1}", VirtualPathRoot.TrimEnd('/'), originalImageName));

            defaultImagePath = ECContext.Current.MapPath(string.Format("{0}/{1}", VirtualPathRoot.TrimEnd('/'), defaultImageName));

            // 没有指定原始图片或指定图片不存在，则设置为默认显示图片
            if (string.IsNullOrEmpty(originalImageName) || !File.Exists(originalImagePath))
                originalImagePath = defaultImagePath;

            ImageGenerateRequest request = new ImageGenerateRequest(originalImagePath, requestWidth, requestHeight);
            request.ResizeMode = ECContext.Current.GetFromQueryString<ImageResizeMode>("m", ImageResizeMode.Fit);
            request.DefaultImagePath = defaultImagePath;

            // 如果请求的图片与原始图片大小一致
            if (request.IsRequestOriginalImage)
                request.ThumbnailImagePath = request.ImagePath;

            return request;
        }

        private Image GetImageThroughTransforms(Image image)
        {
            Image temp = image;

            foreach (var tran in ImageTransforms)
            {
                temp = tran.ProcessImage(temp);
            }
            return temp;
        }

        private Image GetImageThroughTransforms(byte[] buffer)
        {
            MemoryStream memoryStream = new MemoryStream(buffer);
            return GetImageThroughTransforms(Image.FromStream(memoryStream));
        }

        private void RenderImage(Image image, Stream outStream)
        {
            //MemoryStream memoryStream = new MemoryStream();

            //image.Save(memoryStream, ContentType);
            //byte[] arr = memoryStream.GetBuffer();
            //outStream.Write(arr, 0, arr.Length);
            image.Save(outStream, ContentType);
        }
    }
}
